home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
OS2
/
MS_SH200.ARJ
/
SYSTEM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-21
|
38KB
|
1,729 lines
/* MS-DOS System Function with Swaping - system (3C)
*
* MS-DOS System - Copyright (c) 1990,1,2 Data Logic Limited.
*
* This code is subject to the following copyright restrictions:
*
* 1. Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice is duplicated in the
* source form.
*
* Author:
* Ian Stewartson
* Data Logic, Queens House, Greenhill Way
* Harrow, Middlesex HA1 1YR, UK.
* istewart@datlog.co.uk or ukc!datlog!istewart
*
* $Header: c:/usr/src/shell/RCS/system.c 2.0 1992/05/21 16:49:54 Ian_Stewartson Exp $
*
* $Log: system.c $
* Revision 2.0 1992/05/21 16:49:54 Ian_Stewartson
* MS-Shell 2.0 Baseline release
*
*
* MODULE DEFINITION:
*
* This is a version of the standard system(3c) library function. The only
* difference is that it supports swapping and MS-SHELL EXTENDED_LINE
* processing.
*
* To get the OS2 version, compile with -DOS2
*
* There are four macros which can be changed:
*
* GET_ENVIRON To get a variable value from the environment
* FAIL_ENVIRON The result on failure
* FATAL_ERROR Handle a fatal error message
* SHELL_SWITCH The command switch to the SHELL.
*
* This module replaces the standard Microsoft SYSTEM (3C) call. It should
* work with most models. It has been tested in Large and Small model.
* When you link a program using the swapper, the swapper front end
* (swap.obj) must be the first object model on the linker command line so
* that it is located immediately after the PSP. For example:
*
* link swap+x1+x2+x3+system,x1;
* or
* cl -o z1 swap.obj x1.obj x2.obj x3.obj system
*
* The location of the system object is not relevent.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <dirent.h>
#ifdef DL_MAKE
#include "make.h"
#endif
#ifdef OS2
#define INCL_DOSSESMGR
#define INCL_DOSMEMMGR
#define INCL_DOSPROCESS
#define INCL_WINSWITCHLIST
#include <os2.h>
#else
#include <dos.h>
#endif
/*
* Externals declared by the swapper
*/
#ifndef OS2
extern char far cmd_line[]; /* Command line */
extern char far path_line[]; /* Process path */
extern unsigned int far SW_intr; /* interrupt pending */
extern unsigned int far SW_Blocks; /* Number of blocks to read */
extern int far SW_fp; /* File or EMS Handler */
extern unsigned int far SW_EMsize; /* Number of extend memory blks */
extern unsigned long far SW_EMstart; /* Start addr of extend mem */
#define SWAP_TO_DISK 1 /* Swap to disk */
#define SWAP_TO_Ext 2 /* Swap to extended memory */
/* Not recommended - no mgt */
#define SWAP_TO_EMS 3 /* Swap to EMS */
#define SWAP_TO_XMS 4 /* Swap to XMS */
extern unsigned int far SW_Mode; /* Type of swapping to do */
extern unsigned int far SW_EMSFrame; /* EMS Frame segment */
extern bool far SW_I23_InShell; /* In the shell */
/* Functions */
extern int far SA_spawn (char **);
extern void (interrupt far *SW_I23_V) (void); /* Int 23 address */
extern void (far *SW_XMS_Driver) (void); /* XMS Driver Interface */
extern int far SW_XMS_Gversion (void);
extern int far SW_XMS_Allocate (unsigned int);
extern int far SW_XMS_Free (int);
extern unsigned int far SW_XMS_Available (void);
extern void interrupt far SW_Int23 (void); /* Int 23 New address */
extern void interrupt far SW_Int00 (void); /* Int 00 New address */
#endif
#define FFNAME_MAX (PATH_MAX + NAME_MAX + 3)
/* Set these to the appropriate values to get environment variables. For
* make the following values work. Normally, getenv and (char *)NULL should
* be used.
*/
#ifdef DL_MAKE
#define GET_ENVIRON(p) GetMacroValue (p)
#define FAIL_ENVIRON Nullstr
#define FATAL_ERROR(a) PrintFatalError (a)
#define SHELL_SWITCH "-ec"
#else
#define FATAL_ERROR(a) { fputs (a, stderr); fputc ('\n', stderr); exit (1); }
#define GET_ENVIRON(p) getenv (p)
#define FAIL_ENVIRON (char *)NULL
#define SHELL_SWITCH "-c"
#endif
/* Declarations */
/* Open in create mode */
#define O_CMASK (O_WRONLY | O_CREAT | O_TRUNC | O_TEXT)
/* Open in create mode for swap file */
#define O_SMASK (O_RDWR | O_CREAT | O_TRUNC | O_BINARY)
#ifndef OS2
#define CMD_LINE_MAX 127 /* Max command line length */
/* MSDOS Memory Control Block chain structure */
#pragma pack (1)
struct MCB_list {
char MCB_type; /* M or Z */
unsigned int MCB_pid; /* Process ID */
unsigned int MCB_len; /* MCB length */
};
#pragma pack ()
#define MCB_CON 'M' /* More MCB's */
#define MCB_END 'Z' /* Last MCB's */
/* Swap Mode */
#define SWAP_OFF 0x0000 /* No swapping */
#define SWAP_DISK 0x0001 /* Disk only */
#define SWAP_EXTEND 0x0002 /* Extended memory */
#define SWAP_EXPAND 0x0004 /* Expanded memory */
static int Swap_Mode = (SWAP_DISK | SWAP_EXPAND | SWAP_EXTEND);
static char *Swap_File = (char *)NULL;
static char *NoSwapFiles = "No Swap files\n";
static char *MS_emsg = "Warning: %s Error (%x)\n";
static char *XMS_Space = "Warning: %s out of space\n";
static char *SwapFailed = "%s swap failed (%x)\n";
#else
#define CMD_LINE_MAX 255 /* Max command line length */
#endif
char DOS_CommandPath[PATH_MAX + NAME_MAX + 3];
char DOS_CommandLine[CMD_LINE_MAX]; /* Command line */
static char *Extend_file = (char *)NULL;
static char *Extensions [] = { "", ".exe", ".com"};
/*
* Extract field from a line
*/
#define MAX_LINEFIELDS 6 /* Max number of line fields */
typedef struct Fields {
FILE *FP; /* File handler */
char *Line; /* Line buffer */
int LineLength; /* Line Length */
char *Field[MAX_LINEFIELDS]; /* ptr to the start of fields */
} LineFields;
/*
* Program type
*/
static struct ExecutableProcessing {
unsigned char Flags;
unsigned char FieldSep;
char *Name;
} ExecProcessingMode;
/* Flags set a bit to indicate program mode */
#define EP_NONE 0x00 /* Use PSP command line */
#define EP_DOSMODE 0x01 /* Use DOS mode extended line */
#define EP_UNIXMODE 0x02 /* Use UNIX mode extended line */
#define EP_NOEXPAND 0x04 /* Use -f for this command */
#define EP_ENVIRON 0x08 /* Use environ for variable */
#define EP_NOSWAP 0x10 /* Do not swap for this command */
#define EP_COMSPEC 0x20 /* Special for .bat files */
#define EP_EXPORT 0x40 /* Use -m for this command */
#define EP_CONVERT 0x80 /* Use conversion */
/*
* Common fields in EXTENDED_LINE file
*/
#define COMMON_FIELD_COUNT 4
static struct CommonFields {
char *Name;
unsigned char Flag;
} CommonFields [] = {
{ "switch", EP_CONVERT },
{ "export", EP_EXPORT },
{ "noswap", EP_NOSWAP },
{ "noexpand", EP_NOEXPAND }
};
/*
* Functions
*/
#ifndef OS2
static bool near Get_XMS_Driver (void);
static bool near Get_EMS_Driver (void);
static bool near EMS_error (char *, int);
static bool near XMS_error (char *, int);
static int near XMS_Close (void);
static int near EMS_Close (void);
static int near SwapToDiskError (int, char *);
static int near SwapToMemory (int);
static void near SetUpSwapper (void);
#endif
static void near ClearExtendedLineFile (void);
static int near ExecuteProgram (char *, char **);
static bool near FindLocationOfExecutable (char *, char *);
static char * near GenerateTemporaryFileName (void);
static char * near BuildNextFullPathName (char *, char *, char *);
static void near CheckProgramMode (char *);
static unsigned char near CheckForCommonOptions (LineFields *, int, int);
static void near SetCurrentDrive (unsigned int);
static int near SpawnProcess (void);
static int near BuildCommandLine (char *, char **);
static char * near GenerateFullExecutablePath (char *);
static bool near WriteToExtendedFile (int, char *);
static size_t near WhiteSpaceLength (char *, bool *);
static int near StartTheProcess (char *, char **);
static char * near ConvertPathToFormat (char *);
static char * near BuildOS2String (char **, char);
static int ExtractFieldsFromLine (LineFields *);
/*
* System function with swapping
*/
int system (char const *arg2)
{
char *argv[4];
char *ep;
int res, serrno, len;
char p_name[PATH_MAX + NAME_MAX + 3];
char cdirectory[PATH_MAX + 4]; /* Current directory */
char *SaveEV = (char *)NULL;
/* Set up argument array */
argv[1] = SHELL_SWITCH;
if ((argv[0] = GET_ENVIRON ("SHELL")) == FAIL_ENVIRON)
{
argv[0] = GET_ENVIRON ("COMSPEC");
argv[1] = "/c";
}
if (argv[0] == FAIL_ENVIRON)
FATAL_ERROR ("No Shell available");
argv[2] = (char *)arg2;
argv[3] = (char *)NULL;
/* Check to see if the file exists. First check for command.com to use /
* instead of -
*/
if ((ep = strrchr (argv[0], '/')) == (char *)NULL)
ep = argv[0];
else
++ep;
/* Check the program mode */
CheckProgramMode (*argv);
/* Check for command.com */
#ifndef OS2
if (!stricmp (ep, "command.com") || !stricmp (ep, "command"))
{
union REGS r;
r.x.ax = 0x3700;
intdos (&r, &r);
if ((r.h.al == 0) && (_osmajor < 4))
*argv[1] = (char)(r.h.dl);
if (ExecProcessingMode.Flags & EP_CONVERT)
ExecProcessingMode.Flags |= EP_COMSPEC;
}
#endif
/* Convert arguments. If this is COMSPEC for a batch file command, skip over
* the first switch
*/
if (ExecProcessingMode.Flags & EP_COMSPEC)
len = 2;
/*
* Convert from UNIX to DOS format: Slashes to Backslashes in paths and
* dash to slash for switches
*/
if (ExecProcessingMode.Flags & EP_CONVERT)
{
while ((ep = argv[len++]) != (char *)NULL)
{
if (*ep == '-')
*ep = '/';
else
ConvertPathToFormat (ep);
}
}
/* Save the current directory */
getcwd (cdirectory, PATH_MAX + 3);
/* If pass in environment, set up environment variable */
if (ExecProcessingMode.Flags & EP_ENVIRON)
{
if ((SaveEV = GET_ENVIRON (ExecProcessingMode.Name)) != FAIL_ENVIRON)
SaveEV = strdup (ExecProcessingMode.Name);
/* Get some space for the environment variable */
if ((ep = malloc (strlen (ExecProcessingMode.Name) + strlen (argv[1]) +
strlen (argv[2]) + 3)) == (char *)NULL)
{
if (SaveEV != (char *)NULL)
free (SaveEV);
free (ExecProcessingMode.Name);
return -1;
}
sprintf (ep, "%s=%s%c%s", ExecProcessingMode.Name, argv[1],
ExecProcessingMode.FieldSep, argv[2]);
/* Stick it in the environment */
if (putenv (ep))
{
free (ExecProcessingMode.Name);
return -1;
}
argv[1] = ExecProcessingMode.Name;
argv[2] = (char *)NULL;
}
/* Start off on the search path for the executable file */
res = (FindLocationOfExecutable (p_name, argv[0]))
? ExecuteProgram (p_name, argv) : -1;
serrno = errno;
/* Restore the current directory */
SetCurrentDrive (tolower(*cdirectory) - 'a' + 1);
if (chdir (&cdirectory[2]) != 0)
{
fputs ("Warning: current directory reset to /\n", stderr);
chdir ("/");
}
/* Clean up environment. Restore original value */
if (ExecProcessingMode.Flags & EP_ENVIRON)
{
len = strlen (ExecProcessingMode.Name) + 2;
if (SaveEV != (char *)NULL)
len += strlen (SaveEV);
if ((ep = malloc (len)) != (char *)NULL)
{
sprintf (ep, "%s=", ExecProcessingMode.Name,
(SaveEV == (char *)NULL) ? "" : SaveEV);
putenv (ep);
}
/* Release memory */
if (SaveEV != (char *)NULL)
free (SaveEV);
free (ExecProcessingMode.Name);
}
errno = serrno;
return res;
}
/* Exec or spawn the program ? */
static int near ExecuteProgram (char *path, char **parms)
{
int res;
#ifndef OS2
unsigned int size = 0;
int serrno;
unsigned int c_cur = (unsigned int)(_psp - 1);
struct MCB_list far *mp = (struct MCB_list far *)((unsigned long)c_cur << 16L);
#endif
/* Check to see if the file exists */
strcpy (DOS_CommandPath, path);
/* Check we have access to the file */
if (access (DOS_CommandPath, F_OK) != 0)
return -1;
/* Process the command line. If no swapping, we have executed the program */
res = BuildCommandLine (DOS_CommandPath, parms);
#ifdef OS2
SetWindowName ();
ClearExtendedLineFile ();
return res;
#else
if ((ExecProcessingMode.Flags & EP_NOSWAP) ||
(Swap_Mode == SWAP_OFF) || res)
{
ClearExtendedLineFile ();
return res;
}
/* Find the length of the swap area */
while ((mp = (struct MCB_list far *)((unsigned long)c_cur << 16L))->MCB_type
== MCB_CON)
{
if ((mp->MCB_pid != _psp) && (mp->MCB_pid != 0) &&
(mp->MCB_type != MCB_END))
{
ClearExtendedLineFile ();
FATAL_ERROR ("Fatal: Memory chain corrupt");
return -1;
}
c_cur += (mp->MCB_len + 1);
size += mp->MCB_len + 1;
}
/*
* Convert swap size from paragraphs to 16K blocks.
*/
if (size == 0)
size = mp->MCB_len + 1;
SW_Blocks = (size / 0x0400) + 1;
/* OK Now we've set up the FCB's, command line and opened the swap file.
* Get some sys info for the swapper and execute my little assembler
* function to swap us out
*/
/* Ok - 3 methods of swapping. First tranfer to command line to the
* swapper.
*/
SetUpSwapper ();
/* If expanded memory - try that */
if ((Swap_Mode & SWAP_EXPAND) && Get_EMS_Driver ())
{
SW_Mode = 3; /* Set Expanded memory swap */
if ((res = SwapToMemory (SWAP_EXPAND)) != -2)
return res;
}
if ((Swap_Mode & SWAP_EXTEND) && Get_XMS_Driver ())
{
SW_Mode = (SW_fp == -1) ? 2 : 4;/* Set Extended memory or XMS driver */
if ((res = SwapToMemory (SWAP_EXTEND)) != -2)
return res;
}
/* Try the disk if available */
if (Swap_Mode & SWAP_DISK)
{
if ((SW_fp = open ((Swap_File = GenerateTemporaryFileName ()),
O_SMASK, 0600)) < 0)
return SwapToDiskError (ENOSPC, NoSwapFiles);
SW_Mode = 1; /* Set Disk file swap */
/* Execute the program */
res = SpawnProcess ();
/* Close the extended command line file */
ClearExtendedLineFile ();
/* Close the swap file */
serrno = errno;
close (SW_fp);
unlink (Swap_File);
errno = serrno;
/* Check for out of swap space */
if (res == -2)
return SwapToDiskError (errno, "Swap file write failed\n");
/* Return the result */
return res;
}
/* No swapping available - give up */
ClearExtendedLineFile ();
fputs ("swap: All Swapping methods failed\n", stderr);
errno = ENOSPC;
return -1;
#endif
}
#ifndef OS2
/*
* OS2 does not require swapping
*
* Get the XMS Driver information
*/
static bool near Get_XMS_Driver (void)
{
union REGS or;
struct SREGS sr;
unsigned int SW_EMsize; /* Number of extend memory blks */
/* Get max Extended memory pages, and convert to 16K blocks. If Extended
* memory swapping disabled, set to zero
*/
SW_fp = -1; /* Set EMS/XMS handler not */
/* defined */
/* Is a XMS memory driver installed */
or.x.ax = 0x4300;
int86 (0x2f, &or, &or);
if (or.h.al != 0x80)
{
or.x.ax = 0x8800;
int86 (0x15, &or, &or);
SW_EMsize = or.x.ax / 16;
if ((SW_EMsize <= SW_Blocks) ||
(((long)(SW_EMstart - 0x100000L) +
((long)(SW_Blocks - SW_EMsize) * 16L * 1024L)) < 0L))
return XMS_error (XMS_Space, 0);
else
return TRUE;
}
/* Get the driver interface */
or.x.ax = 0x4310;
int86x (0x2f, &or, &or, &sr);
SW_XMS_Driver = (void (far *)())((unsigned long)(sr.es) << 16L | or.x.bx);
/* Support for version 3 of XMS driver */
if ((SW_XMS_Gversion () & 0xff00) < 0x0200)
return XMS_error ("Warning: %s Version < 2\n", 0);
else if (SW_XMS_Available () < (SW_Blocks * 16))
return XMS_error (XMS_Space, 0);
else if ((SW_fp = SW_XMS_Allocate (SW_Blocks * 16)) == -1)
return XMS_error (MS_emsg, errno);
return TRUE;
}
/* Get the EMS Driver information */
static bool near Get_EMS_Driver (void)
{
union REGS or;
struct SREGS sr;
char far *sp;
/* Set EMS/XMS handler not defined */
SW_fp = -1;
or.x.ax = 0x3567;
intdosx (&or, &or, &sr);
sp = (char far *)((unsigned long)(sr.es) << 16L | 10L);
/* If not there - disable */
if (_fmemcmp ("EMMXXXX0", sp, 8) != 0)
return EMS_error ("Warning: %s not available\n", 0);
or.h.ah = 0x40; /* Check status */
int86 (0x67, &or, &or);
if (or.h.ah != 0)
return EMS_error (MS_emsg, or.h.ah);
/* Check version greater than 3.2 */
or.h.ah = 0x46;
int86 (0x67, &or, &or);
if ((or.h.ah != 0) || (or.h.al < 0x32))
return EMS_error ("Warning: %s Version < 3.2\n", 0);
/* get page frame address */
or.h.ah = 0x41;
int86 (0x67, &or, &or);
if (or.h.ah != 0)
return EMS_error (MS_emsg, or.h.ah);
SW_EMSFrame = or.x.bx; /* Save the page frame */
/* Get the number of pages required */
or.h.ah = 0x43;
or.x.bx = SW_Blocks;
int86 (0x67, &or, &or);
if (or.h.ah != 0)
return EMS_error (MS_emsg, or.h.ah);
/* Save the EMS Handler */
SW_fp = or.x.dx;
/* save EMS page map */
or.h.ah = 0x47;
or.x.dx = SW_fp;
int86 (0x67, &or, &or);
return (or.h.ah != 0) ? EMS_error (MS_emsg, or.h.ah) : TRUE;
}
/* Print EMS error message */
static bool near EMS_error (char *s, int v)
{
fprintf (stderr, s, "EMS", v);
Swap_Mode &= ~(SWAP_EXPAND);
EMS_Close ();
return FALSE;
}
/* Print XMS error message */
static bool near XMS_error (char *s, int v)
{
fprintf (stderr, s, "XMS", v);
Swap_Mode &= ~(SWAP_EXTEND);
XMS_Close ();
return FALSE;
}
/* If the XMS handler is defined - close it */
static int near XMS_Close (void)
{
int res = 0;
/* Release XMS page */
if (SW_fp != -1)
res = SW_XMS_Free (SW_fp);
SW_fp = -1;
return res;
}
/* If the EMS handler is defined - close it */
static int near EMS_Close (void)
{
union REGS or;
int res = 0;
if (SW_fp == -1)
return 0;
/* Restore EMS page */
or.h.ah = 0x48;
or.x.dx = SW_fp;
int86 (0x67, &or, &or);
if (or.h.ah != 0)
res = or.h.al;
or.h.ah = 0x45;
or.x.dx = SW_fp;
int86 (0x67, &or, &or);
SW_fp = -1;
return (res) ? res : or.h.ah;
}
#endif
/*
* Find the location of an executable and return it's full path
* name
*/
static bool near FindLocationOfExecutable (char *FullPath, char *name)
{
register char *sp; /* Path pointers */
char *ep;
char *xp1;
int i;
/* Scan the path for an executable */
sp = ((strchr (name, '/') != (char *)NULL) || (*(name + 1) == ':'))
? "" : GET_ENVIRON ("PATH");
do
{
sp = BuildNextFullPathName (sp, name, FullPath);
ep = &FullPath[strlen (FullPath)];
/* Get start of file name */
if ((xp1 = strrchr (FullPath, '/')) == (char *)NULL)
xp1 = FullPath;
else
++xp1;
/* Look up all 3 types */
for (i = 0; i < 3; i++)
{
strcpy (ep, Extensions[i]);
if (access (FullPath, X_OK) == 0)
return TRUE;
}
} while (sp != (char *)NULL);
/* Not found */
errno = ENOENT;
return FALSE;
}
/*
* Generate a temporary filename
*/
static char * near GenerateTemporaryFileName (void)
{
static char tmpfile[FFNAME_MAX];
char *tmpdir; /* Points to directory prefix of pipe */
static int temp_count = 0;
char *sep = "/";
/* Find out where we should put temporary files */
if (((tmpdir = GET_ENVIRON ("TMP")) == FAIL_ENVIRON) &&
((tmpdir = GET_ENVIRON ("HOME")) == FAIL_ENVIRON) &&
((tmpdir = GET_ENVIRON ("TMPDIR")) == FAIL_ENVIRON))
tmpdir = ".";
if (strchr ("/\\", tmpdir[strlen (tmpdir) - 1]) != (char *)NULL)
sep = "";
/* Get a unique temporary file name */
for (;;)
{
sprintf (tmpfile, "%s%ssap%.5u.tmp", tmpdir, sep, temp_count++);
if (access (tmpfile, F_OK) != 0)
break;
}
return tmpfile;
}
/*
* Extract the next path from a string and build a new path from the
* extracted path and a file name
*
* path_s - Path string
* file_s - File name string
* output_s - Output path
*/
static char * near BuildNextFullPathName (register char *path_s,
register char *file_s, char *output_s)
{
register char *s = output_s;
int fsize = 0;
while (*path_s && (*path_s != ';') && (fsize++ < FFNAME_MAX))
*s++ = *path_s++;
if ((output_s != s) && (*(s - 1) != '/') && (fsize++ < FFNAME_MAX))
*s++ = '/';
*s = '\0';
if (file_s != (char *)NULL)
strncpy (s, file_s, FFNAME_MAX - fsize);
output_s[FFNAME_MAX - 1] = 0;
return (*path_s ? ++path_s : (char *)NULL);
}
#ifndef OS2
/*
* Swap to Memory
*/
static int near SwapToMemory (int mode)
{
int res;
int cr;
/* Swap and close memory handler */
res = SpawnProcess ();
cr = (SW_Mode != 3) ? XMS_Close () : EMS_Close ();
if ((res != -2) && cr) /* Report Close error ? */
{
res = -2;
errno = cr;
}
if (res == -2)
(SW_Mode != 3) ? XMS_error (SwapFailed, errno)
: EMS_error (SwapFailed, errno);
else
{
ClearExtendedLineFile ();
return res;
}
/* Failed - disabled */
Swap_Mode &= (~mode);
return res;
}
/*
* Swap to disk error
*/
static int near SwapToDiskError (int error, char *ErrorMessage)
{
/* Close the swap file, if open */
if (SW_fp >= 0)
close (SW_fp);
/* Clean up */
unlink (Swap_File);
Swap_File = (char *)NULL;
Swap_Mode &= (~SWAP_DISK);
fprintf (stderr, ErrorMessage);
errno = error;
return -1;
}
#endif
/* Clear Extended command line file */
static void near ClearExtendedLineFile (void)
{
if (Extend_file != (char *)NULL)
{
unlink (Extend_file);
free ((char *)Extend_file);
}
Extend_file = (char *)NULL;
}
/*
* Check the program type
*/
static void near CheckProgramMode (char *Pname)
{
char *sp, *sp1; /* Line pointers */
int nFields;
char *SPname;
LineFields LF;
struct ExecutableProcessing *PMode = &ExecProcessingMode;
/* Set not found */
PMode->Flags = EP_NONE;
PMode->Name = (char *)NULL;
/* Check not a function */
if ((Pname == (char *)NULL) ||
((sp = GET_ENVIRON ("EXTENDED_LINE")) == FAIL_ENVIRON))
return;
/* Get some memory for the input line and the file name */
sp1 = ((sp1 = strrchr (Pname, '/')) == (char *)NULL)
? Pname : sp1 + 1;
if ((SPname = strdup (sp1)) == (char *)NULL)
return;
if ((LF.Line = malloc (LF.LineLength = 200)) == (char *)NULL)
{
free (SPname);
return;
}
/* Remove terminating .exe etc */
if ((sp1 = strrchr (SPname, '.')) != (char *)NULL)
*sp1 = 0;
/* Open the file */
if ((LF.FP = fopen (sp, "rt")) == (FILE *)NULL)
{
free ((char *)LF.Line);
free (SPname);
return;
}
/* Scan for the file name */
while ((nFields = ExtractFieldsFromLine (&LF)) != -1)
{
if (nFields < 2)
continue;
/* Remove terminating .exe etc */
if ((sp = strrchr (LF.Field[0], '.')) != (char *)NULL)
*sp = 0;
if (stricmp (LF.Field[0], SPname))
continue;
/* What type? */
if (stricmp (LF.Field[1], "unix") == 0)
PMode->Flags = (unsigned char)(EP_UNIXMODE |
CheckForCommonOptions (&LF, nFields, 2));
else if (stricmp (LF.Field[1], "dos") == 0)
PMode->Flags = (unsigned char)(EP_DOSMODE |
CheckForCommonOptions (&LF, nFields, 2));
/* Must have a valid name and we can get memory for it */
else if ((stricmp (LF.Field[1], "environ") == 0) &&
(nFields >= 3) &&
((PMode->Name = strdup (LF.Field[2])) != (char *)NULL))
{
PMode->Flags = EP_ENVIRON;
PMode->FieldSep = 0;
if (nFields >= 4)
PMode->FieldSep = (unsigned char)strtol (LF.Field[3],
(char **)NULL, 0);
if (!PMode->FieldSep)
PMode->FieldSep = ' ';
}
else
PMode->Flags = CheckForCommonOptions (&LF, nFields, 1);
break;
}
fclose (LF.FP);
free ((char *)LF.Line);
free (SPname);
}
/*
* Check for common fields
*/
static unsigned char near CheckForCommonOptions (LineFields *LF, int nFields,
int Start)
{
unsigned char Flags = 0;
int i, j;
for (i = Start; i < nFields; i++)
{
for (j = 0; j < COMMON_FIELD_COUNT; ++j)
{
if (!stricmp (LF->Field[i], CommonFields[j].Name))
{
Flags |= CommonFields[j].Flag;
break;
}
}
}
return Flags;
}
/*
* Set the current drive number and return the number of drives.
*/
static void near SetCurrentDrive (unsigned int drive)
{
#ifdef OS2
DosSelectDisk ((USHORT)drive);
#else
unsigned int ndrives;
_dos_setdrive (drive, &ndrives);
#endif
}
/*
* Convert UNIX format lines to DOS format if appropriate.
* Build Environment variable for some programs.
*/
#ifndef OS2
static int near SpawnProcess (void)
{
void (interrupt far *SW_I00_V) (void); /* Int 00 address */
void (interrupt far *SW_I23_V) (void); /* Int 23 address*/
int res;
#if 0
union REGS r;
unsigned char Save;
r.x.ax = 0x3300;
intdos (&r, &r);
Save = r.h.al;
fprintf (stderr, "Break Status: %s (%u)\n", Save ? "on" : "off", Save);
r.x.ax = 0x3301;
r.h.dl = 1;
intdos (&r, &r);
fprintf (stderr, "Break Status: %s (%u)\n", r.h.al ? "on" : "off", r.h.al);
#endif
/*
* Save current vectors
*/
SW_I00_V = _dos_getvect (0x00);
SW_I23_V = _dos_getvect (0x23);
/*
* Set In shell flag for Interrupt 23, and set to new interrupts
*/
SW_I23_InShell = 0;
_dos_setvect (0x23, SW_Int23);
_dos_setvect (0x00, SW_I00_V);
res = SA_spawn (environ);
/*
* Restore interrupt vectors
*/
_dos_setvect (0x23, SW_I23_V);
#if 0
r.x.ax = 0x3300;
intdos (&r, &r);
fprintf (stderr, "Break Status: %s (%u)\n", r.h.al ? "on" : "off", r.h.al);
r.x.ax = 0x3301;
r.h.dl = Save;
intdos (&r, &r);
#endif
/*
* Check for an interrupt
*/
if (SW_intr)
raise (SIGINT);
return res;
}
#endif
/* Set up command line. If the EXTENDED_LINE variable is set, we create
* a temporary file, write the argument list (one entry per line) to the
* this file and set the command line to @<filename>. If NOSWAPPING, we
* execute the program because I have to modify the argument line
*/
static int near BuildCommandLine (char *path, char **argv)
{
char **pl = argv;
int res, fd;
bool found;
char *ep;
char *new_args[3];
/* Translate process name to MSDOS format */
if (GenerateFullExecutablePath (path) == (char *)NULL)
return -1;
/* Extended command line processing */
Extend_file = (char *)NULL; /* Set no file */
found = ((ExecProcessingMode.Flags & EP_UNIXMODE) ||
(ExecProcessingMode.Flags & EP_DOSMODE)) ? TRUE : FALSE;
if ((*(++pl) != (char *)NULL) && found)
{
char **pl1 = pl;
/* Check parameters don't contain a re-direction parameter */
while (*pl1 != (char *)NULL)
{
if (**(pl1++) == '@')
{
found = FALSE;
break;
}
}
/* If we find it - create a temporary file and write the stuff */
if ((found) &&
((fd = open (Extend_file = GenerateTemporaryFileName (),
O_CMASK, 0600)) >= 0))
{
Extend_file = strdup (Extend_file);
/* Copy to end of list */
while (*pl != (char *)NULL)
{
if (!WriteToExtendedFile (fd, *(pl++)))
return -1;
}
/* Completed write OK */
close (fd);
/* Set up DOS_CommandLine[1] to contain the filename */
memset (DOS_CommandLine, 0, CMD_LINE_MAX);
DOS_CommandLine[1] = ' ';
DOS_CommandLine[2] = '@';
strcpy (&DOS_CommandLine[3], Extend_file);
DOS_CommandLine[0] = (char)(strlen (Extend_file) + 2);
/* Correctly terminate DOS_CommandLine in no swap mode */
#ifndef OS2
if (!(ExecProcessingMode.Flags & EP_NOSWAP) &&
(Swap_Mode != SWAP_OFF))
DOS_CommandLine[DOS_CommandLine[0] + 2] = 0x0d;
#endif
/* If the name in the file is in upper case - use \ for separators */
if (ExecProcessingMode.Flags & EP_DOSMODE)
ConvertPathToFormat (&DOS_CommandLine[2]);
/* OK we are ready to execute */
#ifndef OS2
if ((ExecProcessingMode.Flags & EP_NOSWAP) ||
(Swap_Mode == SWAP_OFF))
{
#endif
new_args[0] = *argv;
new_args[1] = &DOS_CommandLine[1];
new_args[2] = (char *)NULL;
return StartTheProcess (path, new_args);
#ifndef OS2
}
else
return 0;
#endif
}
}
/* Check length of Parameter list */
res = 0;
DOS_CommandLine[0] = 0;
DOS_CommandLine[1] = 0x0d;
/* Skip the first parameter and get the length of the rest */
if (*argv != (char *)NULL)
{
*(ep = DOS_CommandLine + 1) = 0;
while (*pl != (char *)NULL)
{
res += WhiteSpaceLength (*pl, &found);
if (res >= CMD_LINE_MAX)
{
errno = E2BIG;
return -1;
}
if (found)
strcat (strcat (strcat (ep, " \""), *(pl++)), "\"");
else
strcat (strcat (ep, " "), *(pl++));
}
DOS_CommandLine[res + 1] = 0x0d;
}
/* Terminate the line and insert the line length */
DOS_CommandLine[0] = (char)res;
/* If swapping disabled - just execute it */
return StartTheProcess (path, argv);
}
/*
* Convert the executable path to the full path name
*/
static char * near GenerateFullExecutablePath (char *path)
{
char cpath[PATH_MAX + 4];
char npath[PATH_MAX + NAME_MAX + 4];
char n1path[PATH_MAX + 4];
char *p;
int drive;
/* Get path in DOS format */
ConvertPathToFormat (path);
#ifndef OS2
strupr (path);
#else
if (!IsHPFSFileSystem (path))
strupr (path);
#endif
/* Get the current path */
getcwd (cpath, PATH_MAX + 3);
strcpy (npath, cpath);
/* In current directory ? */
if ((p = strrchr (path, '\\')) == (char *)NULL)
{
p = path;
/* Check for a:program case */
if (*(p + 1) == ':')
{
p += 2;
/* Get the path of the other drive */
_getdcwd (tolower (*path) - 'a' + 1, npath, PATH_MAX + 3);
}
}
/* In root directory */
else if ((p - path) == 0)
{
++p;
strcpy (npath, "/");
*npath = *path;
*npath = *cpath;
}
else if (((p - path) == 2) && (*(path + 1) == ':'))
{
++p;
strcpy (npath, "/");
*npath = *path;
}
/* Find the directory */
else
{
*(p++) = 0;
/* Change to the directory containing the executable */
drive = (*(path + 1) == ':') ? tolower (*path) - 'a' + 1 : 0;
/* Save the current directory on this drive */
_getdcwd (drive, n1path, PATH_MAX + 3);
/* Find the directory we want */
if (chdir (path) < 0)
return (char *)NULL;
_getdcwd (drive, npath, PATH_MAX + 3); /* Save its full name */
chdir (n1path); /* Restore the original */
/* Restore our original directory */
if (chdir (cpath) < 0)
return (char *)NULL;
}
if (npath[strlen (npath) - 1] != '\\')
strcat (npath, "\\");
strcat (npath, p);
return strcpy (path, npath);
}
/*
* Write to the Extended File
*/
static bool near WriteToExtendedFile (int fd, char *string)
{
char *sp = string;
char *cp = string;
bool WriteOk = TRUE;
int Length;
if (strlen (string))
{
/* Write the string, converting newlines to backslash newline */
while (WriteOk && (cp != (char *)NULL))
{
if ((cp = strchr (sp, '\n')) != (char *)NULL)
*cp = 0;
if ((Length = strlen (sp)) && (write (fd, sp, Length) != Length))
WriteOk = FALSE;
if (WriteOk && (cp != (char *)NULL))
WriteOk = (write (fd, "\\\n", 2) == 2) ? TRUE : FALSE;
sp = cp + 1;
}
}
if (WriteOk && (write (fd, "\n", 1) == 1))
return TRUE;
close (fd);
ClearExtendedLineFile ();
errno = ENOSPC;
return FALSE;
}
/* Check string for white space */
static size_t near WhiteSpaceLength (char *s, bool *wsf)
{
char *os = s;
*wsf = FALSE;
while (*s)
{
if (isspace (*s))
*wsf = TRUE;
++s;
}
return (size_t)(s - os) + (*wsf ? 3 : 1);
}
/*
* Execute or spawn the process
*/
static int near StartTheProcess (char *path, char **argv)
{
#ifdef OS2
void (*sig_int)(); /* Interrupt signal */
int RetVal;
USHORT usType;
STARTDATA stdata;
#endif
/* Is this a start session option */
#ifndef OS2
return ((ExecProcessingMode.Flags & EP_NOSWAP) || (Swap_Mode == SWAP_OFF))
? spawnve (P_WAIT, path, argv, environ) : 0;
#else
/* In OS/2, we need the type of the program because PM programs have to be
* started in a session (or at least that was the only way I could get them
* to work).
*/
if (DosQAppType (path, &usType))
{
errno = ENOENT;
return -1;
}
/* In OS/2, need to set signal to default so child will process it */
else
{
sig_int = signal (SIGINT, SIG_DFL);
if ((usType & 3) == WINDOWAPI)
{
stdata.Length = sizeof (STARTDATA);
stdata.Related = FALSE;
stdata.FgBg = FALSE;
stdata.TraceOpt = 0;
stdata.PgmTitle = (char *)NULL;
stdata.TermQ = 0;
stdata.Environment = (char *)NULL; /* Build Env */
stdata.InheritOpt = 0;
stdata.SessionType = 3;
stdata.IconFile = (char *)NULL;
stdata.PgmHandle = 0L;
stdata.PgmControl = 8;
stdata.InitXPos = 0;
stdata.InitYPos = 0;
stdata.InitXSize = 100;
stdata.InitYSize = 100;
RetVal = StartTheSession (&stdata, path, argv)
if (stdata.Environment != (char *)NULL)
free (stdata.Environment);
if (stdata.PgmInputs != (char *)NULL)
free (stdata.PgmInputs);
}
else
RetVal = spawnve (P_WAIT, path, argv, environ);
signal (SIGINT, sig_int);
}
return RetVal;
#endif
}
/*
* Convert path format to/from UNIX
*/
static char * near ConvertPathToFormat (char *path)
{
char *s = path;
while ((path = strchr (path, '/')) != (char *)NULL)
*path = '\\';
return s;
}
#ifdef OS2
static int near StartTheSession (STARTDATA *SessionData, char *path,
char **argv)
{
USHORT usType;
USHORT idSession;
USHORT pid;
/* Ensure we always start a PM session in PM */
if (DosQAppType (path, &usType))
{
errno = ENOENT;
return -1;
}
if ((usType & 3) == WINDOWAPI)
SessionData->SessionType = 3;
SessionData->PgmName = path;
if ((SessionData->Environment = BuildOS2String (environ, 0)) == (char *)NULL)
return -1;
if ((SessionData->PgmInputs = BuildOS2String (&argv[1], 0)) == (char *)NULL)
return -1;
if (!(usType = DosStartSession (SessionData, &idSession, &pid)))
return 0;
else
{
errno = ENOENT;
return -1;
}
}
#endif
/*
* Build the OS2 format <value>\0<value>\0 etc \0
*/
static char * near BuildOS2String (char **Array, char sep)
{
int i = 0;
int Length = 0;
char *Output;
char *sp, *cp;
while ((sp = Array[i++]) != (char *)NULL)
Length += strlen (sp) + 1;
Length += 2;
if ((Output = malloc (Length)) == (char *)NULL)
return (char *)NULL;
i = 0;
sp = Output;
/* Build the string */
while ((cp = Array[i++]) != (char *)NULL)
{
while (*sp = *(cp++))
++sp;
*(sp++) = sep;
}
*sp = 0;
return Output;
}
/*
* Get and process configuration line:
*
* <field> = <field> <field> # comment
*
* return the number of fields found.
*/
static int ExtractFieldsFromLine (LineFields *fd)
{
char *cp;
int fieldno;
if (fgets (fd->Line, fd->LineLength - 1, fd->FP) == (char *)NULL)
{
fclose (fd->FP);
return -1;
}
/* Remove the EOL */
if ((cp = strchr (fd->Line, '\n')) != (char *)NULL)
*cp = 0;
/* Remove the comments at end */
if ((cp = strchr (fd->Line, '#')) != (char *)NULL)
*cp = 0;
/* Extract the fields */
cp = fd->Line;
for (fieldno = 0; fieldno < MAX_LINEFIELDS; fieldno++)
{
while (isspace (*cp))
++cp;
if (!*cp)
return fieldno;
fd->Field[fieldno] = cp;
/* First field must be followed by equals */
if (!fieldno)
{
while (!isspace (*cp) && *cp && (*cp != '='))
++cp;
if (*cp && (*cp != '='))
{
*(cp++) = 0;
while (isspace (*cp))
++cp;
}
if (*cp != '=')
return fieldno + 1;
}
/* Process second and third fields */
else
{
while (!isspace (*cp) && *cp)
++cp;
}
*(cp++) = 0;
}
return fieldno;
}
/*
* For multiple model support, we need to transfer to command lines
* to the swapper in far space
*/
#ifndef OS2
static void near SetUpSwapper (void)
{
/* Transfer path name */
_fstrcpy (path_line, DOS_CommandPath);
/* Transfer command line */
_fmemcpy (cmd_line, DOS_CommandLine, CMD_LINE_MAX);
}
#endif
/*
* Test program
*/
#ifdef TEST
int main (int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++)
printf ("Result = %d\n", system (argv[i]));
return 0;
}
#endif